package com.core.rest;

import static io.netty.handler.codec.http.HttpHeaders.isKeepAlive;
import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_LENGTH;
import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE;
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.QueryStringDecoder;
import io.netty.util.CharsetUtil;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import com.core.coder.GameCoder;

public abstract class AbstractHttpHandler {

    //protected AttributeKey<HttpRequest> httpRequest = new AttributeKey<HttpRequest>("httpRequest");
    
    protected String key;
    
    private static final String NOT_VALID_REQUEST = "Not valid request";

    protected HttpRequest httpRequest;
    
    protected GameCoder gameCoder = new GameCoder();

    /**
     * 提供restful的操作
     */
    protected abstract void getData(Map<String, String> params, ChannelHandlerContext ctx);

    /**
     * 向服务器添加数据
     * 
     * @param params
     */
    protected abstract void postData(Map<String, String> params, ChannelHandlerContext ctx);

    /**
     * 通知服务器删除数据
     * 
     * @param params
     */
    protected abstract void deleteData(Map<String, String> params, ChannelHandlerContext ctx);

    /**
     * 通知服务器更新数据
     * 
     * @param params
     */
    protected abstract void updateData(Map<String, String> params, ChannelHandlerContext ctx);

    public void process(Object msg, ChannelHandlerContext ctx, HttpMethod method, HttpRequest request) {
        
        if (msg instanceof HttpContent) {

            HttpContent httpContent = (HttpContent)msg;

            httpRequest = request;

            if (method.equals(HttpMethod.GET)) {//需要向web服务器返回json格式数据

                QueryStringDecoder queryStringDecoder = new QueryStringDecoder(request.getUri());

                Map<String, List<String>> ps = queryStringDecoder.parameters();
                
                String authoKey = null;
                
                if(ps!= null && !ps.isEmpty()){
                    
                    authoKey = ps.get("authoKey").get(0);
                }
                
                if (!authorize(authoKey)){
                    
                    this.sendBackNotValidNotice(ctx);
                    
                    return;
                    
                }

                Map<String, String> p = getParamsAsMap(ps);

                getData(p, ctx);

            } else if (method.equals(HttpMethod.POST)) {//向游戏服务器添加数据

                ByteBuf content = httpContent.content();
                
                if (content.isReadable()) {

                    String params = content.toString(CharsetUtil.UTF_8);
                    
                    QueryStringDecoder queryStringDecoder = new QueryStringDecoder(params, false);

                    Map<String, List<String>> ps = queryStringDecoder.parameters();
                    
                    String authoKey = null;
                    
                    if(ps!= null && !ps.isEmpty()){
                        
                        authoKey = ps.get("authoKey").get(0);
                    }
                    
                    if (!authorize(authoKey)){
                        
                        this.sendBackNotValidNotice(ctx);
                        
                        return;
                        
                    } else {
                        
                        Map<String, String> p = getParamsAsMap(ps);
                        
                        postData(p, ctx);
                    }

                } else {

                    return;
                }

            } else if (method.equals(HttpMethod.DELETE)) {//通知游戏服务器删除数据

                QueryStringDecoder queryStringDecoder = new QueryStringDecoder(request.getUri());

                Map<String, List<String>> ps = queryStringDecoder.parameters();

                String authoKey = null;
                
                if(ps!= null && !ps.isEmpty()){
                    
                    authoKey = ps.get("authoKey").get(0);
                }
                
                if (!authorize(authoKey)){
                    
                    this.sendBackNotValidNotice(ctx);
                    
                    return;
                    
                }

                Map<String, String> p = getParamsAsMap(ps);

                deleteData(p, ctx);

            } else if (method.equals(HttpMethod.PUT)) {//通知服游戏服务器更新数据

                ByteBuf content = httpContent.content();

                if (content.isReadable()) {

                    String params = content.toString(CharsetUtil.UTF_8);

                    QueryStringDecoder queryStringDecoder = new QueryStringDecoder(params, false);

                    Map<String, List<String>> ps = queryStringDecoder.parameters();

                    String authoKey = null;
                    
                    if(ps!= null && !ps.isEmpty()){
                        
                        authoKey = ps.get("authoKey").get(0);
                    }
                    
                    if (!authorize(authoKey)){
                        
                        this.sendBackNotValidNotice(ctx);
                        
                        return;
                        
                    }

                    Map<String, String> p = getParamsAsMap(ps);

                    updateData(p, ctx);
                    
                } else {

                    return;
                }

            }

        }

    }

    private Map<String, String> getParamsAsMap(Map<String, List<String>> ps) {

        Map<String, String> paramsResult = new HashMap<String, String>();

        if (!ps.isEmpty()) {

            for (Entry<String, List<String>> p : ps.entrySet()) {

                String key = p.getKey();

                List<String> vals = p.getValue();

                if (vals == null || vals.isEmpty()) {

                    continue;
                }

                else {

                    String value = "authoKey".equals(key) ? vals.get(0) : this.decrypt(vals.get(0));
					paramsResult.put(key, value);

                }

            }
        }

        return paramsResult;
    }

    public FullHttpResponse wrapContent(String content) {

        String responseContent = new String(content);
        
        responseContent = this.encrypt(responseContent);

        byte [] bytes = responseContent.getBytes(CharsetUtil.UTF_8);

        ByteBuf buf = Unpooled.buffer(bytes.length);

        buf.writeBytes(bytes);

        FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK, buf);

        response.headers().set(CONTENT_TYPE, "text/plain");

        response.headers().set(CONTENT_LENGTH, bytes.length);

        return response;
    }

    public void sendResponse(ChannelHandlerContext ctx, FullHttpResponse response) {

        boolean keepAlive = isKeepAlive(httpRequest);

        if (!keepAlive) {

            ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
            ctx.close();

        } else {
            
            ctx.write(response);
            ctx.flush();
            ctx.close();
        }

    }
    
    public abstract AbstractHttpHandler deepCopy();
    
    /**
     * 验证是否合法
     * 
     * implemented by longrm
     * 
     * @param authoKey
     * @return
     */
    public boolean authorize(String authoKey){
        try {
			return gameCoder.authorize(authoKey);
		} catch (Exception e) {
			// TODO logger?
			e.printStackTrace();
		}
        return false;
    }
    
    /**
     * 解密参数
     * @param text
     * @return
     */
    public String decrypt(String text) {
    	try {
			return gameCoder.decrypt(text);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    	return null;
    }
    
    /**
     * 加密后，写回web服务器
     * 
     * implemented by longrm
     * 
     * @param text
     * @return
     */
    public String encrypt(String text){
        try {
			return gameCoder.encrypt(text);
		} catch (Exception e) {
			// TODO logger?
			e.printStackTrace();
		}
        return null;
    }
    
    private void sendBackNotValidNotice(ChannelHandlerContext ctx){
        
        FullHttpResponse response = wrapContent(NOT_VALID_REQUEST);

        sendResponse(ctx, response);
    }
}
